#include "csv2sql.h"

namespace csv2sql
{
  
    Parser::Parser(Options *o, IWriter *w)
    {
      options = o;
      writer = w;
      init();
    }
    
    void Parser::init()
    {
      abort = false;
      mode = PM_READY;
    }
    
    void Parser::Abort()
    {
      abort = true;
    }
    
    bool Parser::Parse()
    {
      
      FILE * pFile;
      int c;
      ParserMode headMode = PM_HEAD;
      int colNum = 0, rowNum = 0;
      pFile=fopen (options->file,"r");
      
      if (pFile==NULL)
      {
        perror ("\nError opening file.\n\n");
        return false;
      }
      else
      {
        writer->Start();
        while (c != EOF && !abort) 
        {
          
          c = fgetc(pFile);
      
          // fprintf(stderr,"%c",c);
 
          if (c == EOF)
            break;
                
          switch (mode)
          {
            case PM_READY: 
            {
              // blank row (probably \n after \r)
              if ( strchr(options->row_end, c) != NULL ) 
              {
                // writer->EndRow(PM_CELL | PM_EMPTY | headMode);
                // headMode = PM_NONE;
                // colNum=0;
                continue;
              }
              if (!colNum++)
                rowNum++;
              // fprintf(stderr,"{%i}[%i]"colNum,rowNum);
              // quoted cell start
              if ( strchr(options->quote, c) != NULL ) 
              {
                currentQuote = c;
                mode = PM_QCELL;
                if (colNum == 1)
                  writer->StartRow(mode | headMode);
                else
                  writer->StartCell(mode | headMode);
                continue;
              }
              // blank cell
              if ( strchr(options->col_end, c) != NULL ) 
              {
                if (colNum == 1)
                  writer->StartRow(PM_CELL | PM_EMPTY | headMode);
                else
                  writer->StartCell(PM_CELL | PM_EMPTY | headMode);
                writer->EndCell(PM_CELL | PM_EMPTY | headMode);
                mode = PM_READY;
                continue;
              }           
              // escaped char
              if ( strchr(options->escape, c) != NULL ) 
              {
                c = fgetc(pFile);
              }
              // non-quoted cell
              mode = PM_CELL;
              if (colNum == 1)
                writer->StartRow(mode | headMode);
              else
                writer->StartCell(mode | headMode);
              writer->Write(c, mode | headMode);
              break;
            }
            case PM_CELL:
            {
              // cell end
              if ( strchr(options->col_end, c) != NULL ) 
              {
                writer->EndCell(mode | headMode);
                mode = PM_READY;
                continue;
              }
              // row end
              if ( strchr(options->row_end, c) != NULL ) 
              {
                writer->EndRow(mode | headMode);
                headMode = PM_NONE;
                mode = PM_READY;
                colNum=0;
                continue;
              }
              // escaped char
              if ( strchr(options->escape, c) != NULL ) 
              {
                c = fgetc(pFile);
              }
              // cell content
              writer->Write(c, mode | headMode);
              break;
            }
            case PM_QCELL:
            {
              // end quote?
              if ( c == currentQuote) 
              {
                char c2 = fgetc(pFile);
                if (c2 == EOF)
                { 
                  writer->Write(c, mode | headMode);
                  writer->EndRow(mode | headMode);
                  c = EOF;
                  continue;
                }
                // double-escaped quote
                if ( currentQuote == c2 ) 
                {
                  writer->Write(c, mode | headMode);
                  continue;
                }
                // cell end
                if ( strchr(options->col_end, c2) != NULL ) 
                {
                  currentQuote = 0;
                  writer->EndCell(mode | headMode);
                  mode = PM_READY;
                  continue;
                }
                // row end
                if ( strchr(options->row_end, c2) != NULL ) 
                {
                  currentQuote = 0;
                  writer->EndRow(mode | headMode);
                  headMode = PM_NONE;
                  mode = PM_READY;
                  colNum=0;
                  continue;
                }
                // non-escaped internal quote
                writer->Write(c, mode | headMode);
                mode = PM_READY;
                continue;
              }
              // escaped char
              if ( strchr(options->escape, c) != NULL ) 
              {
                c = fgetc(pFile);
              }
              // cell content
              writer->Write(c, mode | headMode);
              break;
            }
            default:
            {
              fprintf(stderr,"\nError: Parser in undetermined state.\n\n");
              return false;
            }
          }
            
        }
        fclose (pFile);
        writer->End();
      }
      return true;
    }

}
